package com.loan.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.loan.entity.*;
import com.loan.exception.*;
import com.loan.mappers.*;
import com.loan.service.ContractService;
import com.loan.util.ContractNumber;
import com.loan.util.RepaymentCompute;
import com.loan.vo.ContractArray;
import com.loan.vo.ContractEmp;
import com.loan.vo.ContractVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @ClassName: ContractServiceImpl
 * @Author: wYin
 * @Date: 2022/1/18 10:47
 */
@Service("contractService")
@SuppressWarnings("all")
public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> implements ContractService {
    @Autowired
    private ContractMapper contractMapper;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private EmpMapper empMapper;

    @Autowired
    private CustomerMapper customerMapper;

    @Autowired
    private RepaymentMapper repaymentMapper;

    @Autowired
    private UserMapper userMapper;

    /**
     * 功能描述: <br>
     * 实现合同表信息的添加（未放款状态）-添加
     * 注意：添加合同信息是需要校验表中主要字段的有效性
     * @Param: [contract]
     * @Return: boolean
     * @Author: wYin
     * @Date: 2022/1/18 11:47
     */
    @Override
    public boolean insert(Contract contract) {
        //判断当前产品是否存在
        Product product = productMapper.selectById(contract.getProId());
        if(product==null){
            throw new ProductException("当前产品不存在");
        }

        Emp emp = empMapper.selectById(contract.getEmpId());
        if(emp==null){
            throw new EmpException("当前业务员不存在");
        }
        Customer customer = customerMapper.selectById(contract.getCusId());
        if(customer==null){
            throw new CustomerException("当前客户还没有进行客户信息登记");
        }
        //生成合同编号
        contract.setNumber(judgeNumber());
        contract.setFrequency(0);//违约次数
        contract.setTime(new Date());//签订时间
        contract.setLoan("n");//是否放款
        //欠款金额：贷款本金+利息
//        BigDecimal totalMoney = contract.getMoney().add((contract.getMoney().multiply(product.getRate())).setScale(2,
//                BigDecimal.ROUND_HALF_DOWN));
//        contract.setDebt(totalMoney);
        contract.setConfirm("y");//提交合同即客户完成确定
        //执行合同添加操作--此时合同还未放款
        int row = contractMapper.insert(contract);
        if(row>0){//添加合同表数据成功
            //添加流程表数据
            return true;
        }
        return false;
    }

    @Override
    public List<Contract> getContracts(Contract contract) {
        return null;
    }

    /**
     * 功能描述: <br>
     * 更新业务信息:过程中需要匹配客户、业务员、合同编号进行校验
     * @Param: [contract]
     * @Return: boolean
     * @Author: wYin
     * @Date: 2022/1/18 18:36
     */
    @Override
    public int updateContractInfo(Contract contract) {
        //验证业务员的合法性(根据业务员id）
        Emp emp = empMapper.selectById(contract.getEmpId());
        if(emp==null){
            throw new EmpException("当前业务员不存在，操作不合法");
        }
        //判断当前客户信息是否存在
        Customer customer = customerMapper.selectById(contract.getCusId());
        if(customer==null){
            throw new CustomerException("当前客户不存在");
        }
        //根据合同表查询合同信息
        QueryWrapper<Contract> query = new QueryWrapper<>();
        query.eq("number",contract.getNumber());
        Contract contract1 = contractMapper.selectOne(query);
        if(contract1==null){
            throw new ContractException("当前合同不存在");
        }
        if(contract1.getCusId()!=contract.getCusId()){
            throw new CustomerException("当前客户信息与合同信息不匹配");
        }
        if(contract1.getId()!=contract.getId()){
            throw new ContractException("当前合同对应的id不匹配");
        }
        //如果传入的业务员id相同-则可以进行信息的修改
        if(contract.getEmpId()==contract1.getEmpId()){
            //判断当前合同是否已经放款（如放款则不允许）
            if ("y".equals(contract1.getLoan())) {
                throw new ContractException("当前合同已经放款，不能进行合同修改");
            }
            contract.setTime(null);
            //判断是否有更新产品
            if (contract.getProId()!=contract1.getProId()) {
                //判断当前更新产品是否存在
                Product product = productMapper.selectById(contract.getProId());
                if(product==null){
                    throw new ProductException("当前更新的产品不存在");
                }
                //存在则需要检查当前产品的贷款额度与客户贷款额度是否超出
                if (contract.getMoney().compareTo(product.getMaxMoney())>0) {
                    throw new ProductException("当前的贷款额度操作了该产品的最大贷款额度，建议更换产品");
                }
            }
            int row = contractMapper.updateById(contract);
            if(row>0){
                return 1;//更新合同信息
            }
        }else{
//            执行业务员信息的id
            contract1.setEmpId(contract.getEmpId());
            int row = contractMapper.updateById(contract1);
            if(row>0){
                return 2;//更新业务员
            }
        }
        return 0;
    }

    /**
     * 功能描述: <br>
     * 单一更新合同表的放款情况
     *  通过传入的业务员id和合同编号进行校验进行合同更新
     *  通过合同编号进行合同表数据的修改
     * @Param: [contract]
     * @Return: boolean
     * @Author: wYin
     * @Date: 2022/1/18 18:43
     */
    @Override
    @Transactional
    public boolean updateContractLoan(Contract contract) {
        //通过合同编号查询，以此判断业务员是否合法
        Contract contract1 = contractMapper.selectOne(new QueryWrapper<Contract>().eq("number", contract.getNumber()));
        if(contract1==null){
            throw new ContractException("当前合同编号有误，无法进行匹配");
        }
        if(contract1.getEmpId()!=contract.getEmpId()){
            throw new EmpException("不是同一个业务员进行操作，不符合要求，不能进行操作");
        }
        Product product1 = productMapper.selectById(contract1.getProId());
        //欠款金额：贷款本金+利息
        BigDecimal totalMoney = contract1.getMoney().add((contract1.getMoney().multiply(product1.getRate())).setScale(2,
                BigDecimal.ROUND_HALF_DOWN));
//        执行合同放款的更改（根据合同编号更改合同放款）
        int row = contractMapper.updateLoan(totalMoney,contract.getNumber());
        if(row>0){
            //生成还款表信息
            //得到产品的期限
            Product product = productMapper.selectById(contract1.getProId());
            RepaymentCompute repaymentCompute = new RepaymentCompute(product,contract1.getMoney());
            BigDecimal monthlyPrincipal = repaymentCompute.getMonthlyPrincipal();//每月本金
            BigDecimal monthlyInterest = repaymentCompute.getMonthlyInterest();//每月利息
            Integer time = product.getTime();//产品期限
            //得到时间
            Date date = new Date();

            for (Integer i = 0; i < time; i++) {
                //还款表数据添加
                Repayment repayment = new Repayment();
                repayment.setConId(contract1.getId());//合同id
                repayment.setEmpId(contract1.getEmpId());//业务员id
                repayment.setMoney(monthlyInterest.add(monthlyPrincipal));//还款金额
                //生成时间
                if (date.getMonth() < 11) {
                    date.setMonth(date.getMonth() + 1);
                    repayment.setAppoTime(date);
                } else {
                    date.setMonth(0);
                    date.setYear(date.getYear() + 1);
                    repayment.setAppoTime(date);
                }
                repayment.setCusId(contract1.getCusId());//客户id
                repayment.setPrincipal(monthlyPrincipal);//本金
                repayment.setInterest(monthlyInterest);//利息
                //执行生成还款表数据
                repaymentMapper.insert(repayment);
            }
            return true;
        }
        return false;
    }

    /**
     * @Desc: 得到单一合同表级联所有信息
     * @Param: [contractVO] 接收合同编号、合同id、业务员id或用户ID
     * @Return: com.loan.entity.ContractAllInfo
     * @Author: wYin
     * @Date: 2022/1/19 20:57
     */
    public Contract getSingleContract(ContractVO contractVO) {
        //判断当前是用户登录还是业务员登录（单一选择：如果有用户ID则为登录、反之则为业务员登录）
        if(contractVO.getUserId()!=null){
            //查询用户是否合法、并且比较用户与当前合同客户之间是否是统一身份
            User user = userMapper.selectById(contractVO.getUserId());
            if(user==null){
                throw new UserException("未查询到当前用户的信息");
            }
            //查询贷款客户中是否存在当前用户
            Customer customer = customerMapper.selectOne(new QueryWrapper<Customer>().eq("user_id", user.getId()));
            if(customer==null){
                throw new CustomerException("未查询到任何贷款信息");
            }
            //执行查询
            Contract contract = contractMapper.selectById(contractVO.getContract().getId());
            if(contract==null){
                throw new ContractException("没有查询到当前合同的信息");
            }
            if(!contractVO.getContract().getNumber().equals(contract.getNumber())){
                throw new ContractException("当前合同的编号与你提供的编号不同");
            }
            //根据合同新查询出响应信息(用户登录：查询出产品、业务员、合同信息
            Emp empInfo = empMapper.getEmpInfo(contract.getEmpId());//操作合同的员工信息
            Product product = productMapper.selectById(contract.getProId());
            contract.setProduct(product);
            contract.setEmp(empInfo);
            return contract;
        }else{
            if(contractVO.getContract().getEmpId()==null){
                throw new EmpException("业务员没有进行登录");
            }
            //判断业务员的合法性
            Emp emp = empMapper.selectById(contractVO.getContract().getEmpId());
            if(emp==null){
                throw new EmpException("当前业务员不合法");
            }
            if(!"y".equals(emp.getStatus())){
                throw new EmpException("你没有操作的权限（可能已经离职）");
            }
//            根据合同编号和合同id查询
            Contract contract = contractMapper.selectOne(new QueryWrapper<Contract>().and(t -> t.eq("id", contractVO.getContract().getId()).eq(
                    "number", contractVO.getContract().getNumber())));
            if(contract==null){
                throw new ContractException("合同编号和id不匹配，无法查询");
            }
            if(contract.getEmpId()!=contractVO.getContract().getEmpId()){
                throw new EmpException("你无法错误当前合同");
            }
            Product product = productMapper.selectById(contract.getProId());
            contract.setProduct(product);
            Customer customer = customerMapper.selectById(contract.getCusId());
            User user = userMapper.selectById(customer.getUserId());
            contract.setUser(user);
            return contract;
        }
    }

    /**
     * @Desc: 员工查询合同订单
     * @Param: [emp]
     * @Return: java.util.List<com.loan.entity.Contract>
     * @Author: wYin
     * @Date: 2022/1/20 16:23
     */
    @Override
    public  List<Contract> getAllContractInfo(Emp emp) {
        //查询员工的合法性
        Emp emp1 =
                empMapper.selectOne(new QueryWrapper<Emp>().and(t->t.eq("id",emp.getId()).eq("account",emp.getAccount())));
        if(emp1==null){
            throw new EmpException("没有查询到当前员工信息");
        }
        if(!"y".equals(emp1.getStatus())){
            throw new EmpException("当前员工状态不能进行访问");
        }
        //根据员工的id查询符合的合同订单
        List<Contract> list = contractMapper.selectList(new QueryWrapper<Contract>().eq("emp_id", emp.getId()));
        if(list.size()==0){
            throw new ContractException("没有查询到当前员工处理的合同信息");
        }
        for (Contract contract : list) {
            Product product = productMapper.selectById(contract.getProId());
            contract.setProduct(product);
            //客户信息
            Customer customer = customerMapper.selectById(contract.getCusId());
            User user = userMapper.selectById(customer.getUserId());
            user.setPassword(null);
            user.setGender(null);
            user.setAge(null);
            contract.setUser(user);
            emp1.setPassword(null);
            emp1.setGender(null);
            emp1.setAccount(null);
            contract.setEmp(emp1);
        }
        return list;
    }

    /**
     * @Desc: 根据用户传入的用户的id和账户校验来查询合同信息
     * @Param: [user]
     * @Return: java.util.List<com.loan.entity.Contract>
     * @Author: wYin
     * @Date: 2022/1/20 14:12
     */
    @Override
    public List<Contract> userGetContract(User user) {
        User user1 = userMapper.selectById(user.getId());
        if(user1==null){
            throw new UserException("当前用户不存在");
        }
        if(!user.getUsername().equals(user1.getUsername())){
            throw new UserException("当前账户和id不匹配");
        }
        //根据用户查客户信息
        Customer customer = customerMapper.selectOne(new QueryWrapper<Customer>().eq("user_id", user1.getId()));
        if(customer==null){
            throw new CustomerException("当前你还没有任何贷款信息");
        }
        List<Contract> list = contractMapper.selectList(new QueryWrapper<Contract>().eq("cus_id", customer.getId()));
        if(list.size()==0){
            throw new ContractException("没有查询到合同信息");
        }
        for (Contract contract : list) {
//            查询业务员信息
            Emp emp = empMapper.selectById(contract.getEmpId());
            emp.setPassword(null);
            emp.setGender(null);
            emp.setAccount(null);
            contract.setEmp(emp);
            user1.setPassword(null);
            user1.setGender(null);
            user1.setAge(null);
            contract.setUser(user);
        }
        return list;
    }

    /**
     * @Desc: 接收员工id和放款状态查询得到当前员工为处理的放款
     * @Param: [conEmp]
     * @Return: java.util.List<com.loan.entity.Contract>
     * @Author: wYin
     * @Date: 2022/1/23 15:19
     */
    @Override
    public List<Contract> getLoanStatusIsN(ContractEmp conEmp) {
        //查询员工的合法性
        Emp emp1 =
                empMapper.selectOne(new QueryWrapper<Emp>().and(t->t.eq("id",conEmp.getEmp().getId()).eq("account",
                        conEmp.getEmp().getAccount())));
        if(emp1==null){
            throw new EmpException("没有查询到当前员工信息");
        }
        if(!"y".equals(emp1.getStatus())){
            throw new EmpException("当前员工状态不能进行访问");
        }
        //根据员工的id查询符合的合同订单
        List<Contract> list =
                contractMapper.selectList(new QueryWrapper<Contract>().eq("emp_id", conEmp.getEmp().getId()).eq("loan",
                        conEmp.getStatus()));
        if(list.size()==0){
            throw new ContractException("未查询到还未处理的放款");
        }
        for (Contract contract : list) {
            Product product = productMapper.selectById(contract.getProId());
            contract.setProduct(product);
            //客户信息
            Customer customer = customerMapper.selectById(contract.getCusId());
            User user = userMapper.selectById(customer.getUserId());
            user.setPassword(null);
            user.setGender(null);
            user.setAge(null);
            contract.setUser(user);
            emp1.setPassword(null);
            emp1.setGender(null);
            emp1.setAccount(null);
            contract.setEmp(emp1);
        }
        return list;
    }

    @Override
    @Transactional
    public Boolean batchUpdateLoan(List<ContractArray> contractArrays) {
        List<Contract> contracts = new ArrayList<>();
        for (ContractArray contractArray : contractArrays) {
            Contract contract = new Contract();
            contract.setEmpId(contractArray.getEmpId());
            contract.setNumber(contractArray.getNumber());
            contracts.add(contract);
        }
        try {
            for (Contract contract : contracts) {
                boolean b = updateContractLoan(contract);
                if(!b){
                    throw new ContractException("处理编号为："+contract.getNumber()+"失败，操作被撤回");
                }
            }
        }catch (Exception ex){
            throw new ContractException("批量操作放款数据失败，原因是："+ex.getMessage());
        }
        return true;
    }

    /**
     * 功能描述: <br>
     * 判断合同编号是否存在以及返回不存在的合同编号（生成合同编号）
     * @Param: []
     * @Return: java.lang.String
     * @Author: wYin
     * @Date: 2022/1/18 17:24
     */
    public String judgeNumber(){
        String number = ContractNumber.getNumber();
        //查询当前编号是否已经存在
        int num = contractMapper.getNumber(number);
        if(num!=0){
            judgeNumber();
        }
        return number;
    }
}
